/src/gmpy_context.c
C | 1210 lines | 1056 code | 105 blank | 49 comment | 192 complexity | b6d49f7521d13f2626efc8d864dc6753 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, LGPL-2.1
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * gmpy_context.c *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision *
- * libraries. *
- * *
- * Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, *
- * 2008, 2009 Alex Martelli *
- * *
- * Copyright 2008, 2009, 2010, 2011, 2012, 2013 Case Van Horsen *
- * *
- * This file is part of GMPY2. *
- * *
- * GMPY2 is free software: you can redistribute it and/or modify it under *
- * the terms of the GNU Lesser General Public License as published by the *
- * Free Software Foundation, either version 3 of the License, or (at your *
- * option) any later version. *
- * *
- * GMPY2 is distributed in the hope that it will be useful, but WITHOUT *
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public *
- * License for more details. *
- * *
- * You should have received a copy of the GNU Lesser General Public *
- * License along with GMPY2; if not, see <http://www.gnu.org/licenses/> *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- /* A GMPyContextObject contains an instance of the C struct gmpy_context
- * and a PyObject* used to reference the enclosing instance when used as a
- * context manager in Python.
- *
- * gmpy2 uses a global pointer "context" to refer to the active
- * GMPyContextObject.
- *
- * WARNING: The context manager is not thread-safe. This may be fixed in a
- * future version.
- */
- /* Create and delete Context objects. */
- static PyObject *
- GMPyContext_new(void)
- {
- GMPyContextObject *result;
- if ((result = PyObject_New(GMPyContextObject, &GMPyContext_Type))) {
- result->ctx.mpfr_prec = DBL_MANT_DIG;
- result->ctx.mpfr_round = MPFR_RNDN;
- result->ctx.emax = MPFR_EMAX_DEFAULT;
- result->ctx.emin = MPFR_EMIN_DEFAULT;
- result->ctx.subnormalize = 0;
- result->ctx.underflow = 0;
- result->ctx.overflow = 0;
- result->ctx.inexact = 0;
- result->ctx.invalid = 0;
- result->ctx.erange = 0;
- result->ctx.divzero = 0;
- result->ctx.trap_underflow = 0;
- result->ctx.trap_overflow = 0;
- result->ctx.trap_inexact = 0;
- result->ctx.trap_invalid = 0;
- result->ctx.trap_erange = 0;
- result->ctx.trap_divzero = 0;
- result->ctx.trap_expbound = 0;
- #ifdef WITHMPC
- result->ctx.real_prec = -1;
- result->ctx.imag_prec = -1;
- result->ctx.real_round = -1;
- result->ctx.imag_round = -1;
- result->ctx.allow_complex = 0;
- #endif
- }
- return (PyObject*)result;
- };
- static void
- GMPyContext_dealloc(GMPyContextObject *self)
- {
- PyObject_Del(self);
- };
- PyDoc_STRVAR(doc_context_ieee,
- "ieee(bitwidth) -> context\n\n"
- "Return a new context corresponding to a standard IEEE floating point\n"
- "format. The currently supported precisions are 32, 64, and 128 bits.");
- static PyObject *
- GMPyContext_ieee(PyObject *self, PyObject *other)
- {
- long bitwidth;
- GMPyContextObject *result;
- bitwidth = PyIntOrLong_AsLong(other);
- if (bitwidth == -1 && PyErr_Occurred()) {
- TYPE_ERROR("ieee() requires 'int' argument");
- return NULL;
- }
- if (bitwidth == 32) {
- result = (GMPyContextObject*)GMPyContext_new();
- if (result) {
- result->ctx.subnormalize = 1;
- result->ctx.mpfr_prec = 24;
- result->ctx.emax = 128;
- result->ctx.emin = -148;
- }
- return (PyObject*)result;
- }
- else if (bitwidth == 64) {
- result = (GMPyContextObject*)GMPyContext_new();
- if (result) {
- result->ctx.subnormalize = 1;
- result->ctx.mpfr_prec = 53;
- result->ctx.emax = 1024;
- result->ctx.emin = -1073;
- }
- return (PyObject*)result;
- }
- else if (bitwidth == 128) {
- result = (GMPyContextObject*)GMPyContext_new();
- if (result) {
- result->ctx.subnormalize = 1;
- result->ctx.mpfr_prec = 113;
- result->ctx.emax = 16384;
- result->ctx.emin = -16493;
- }
- return (PyObject*)result;
- }
- else {
- VALUE_ERROR("bitwidth must be 32, 64, or 128");
- return NULL;
- }
- }
- /* Create and delete ContextManager objects. */
- static PyObject *
- GMPyContextManager_new(void)
- {
- return (PyObject*)PyObject_New(GMPyContextManagerObject,
- &GMPyContextManager_Type);
- };
- static void
- GMPyContextManager_dealloc(GMPyContextManagerObject *self)
- {
- PyObject_Del(self);
- };
- /* Helper function to convert to convert a rounding mode to a string. */
- static PyObject *
- _round_to_name(int val)
- {
- if (val == MPFR_RNDN) return Py2or3String_FromString("RoundToNearest");
- if (val == MPFR_RNDZ) return Py2or3String_FromString("RoundToZero");
- if (val == MPFR_RNDU) return Py2or3String_FromString("RoundUp");
- if (val == MPFR_RNDD) return Py2or3String_FromString("RoundDown");
- if (val == MPFR_RNDA) return Py2or3String_FromString("RoundAwayZero");
- if (val == GMPY_DEFAULT) return Py2or3String_FromString("Default");
- return NULL;
- };
- static PyObject *
- GMPyContext_repr(GMPyContextObject *self)
- {
- PyObject *format;
- PyObject *tuple;
- PyObject *result = NULL;
- int i = 0;
- #ifdef WITHMPC
- tuple = PyTuple_New(23);
- #else
- tuple = PyTuple_New(18);
- #endif
- if (!tuple) return NULL;
- #ifdef WITHMPC
- format = Py2or3String_FromString(
- "context(precision=%s, real_prec=%s, imag_prec=%s,\n"
- " round=%s, real_round=%s, imag_round=%s,\n"
- " emax=%s, emin=%s,\n"
- " subnormalize=%s,\n"
- " trap_underflow=%s, underflow=%s,\n"
- " trap_overflow=%s, overflow=%s,\n"
- " trap_inexact=%s, inexact=%s,\n"
- " trap_invalid=%s, invalid=%s,\n"
- " trap_erange=%s, erange=%s,\n"
- " trap_divzero=%s, divzero=%s,\n"
- " trap_expbound=%s,\n"
- " allow_complex=%s)"
- );
- #else
- format = Py2or3String_FromString(
- "context(precision=%s,\n"
- " round=%s,\n"
- " emax=%s, emin=%s,\n"
- " subnormalize=%s,\n"
- " trap_underflow=%s, underflow=%s,\n"
- " trap_overflow=%s, overflow=%s,\n"
- " trap_inexact=%s, inexact=%s,\n"
- " trap_invalid=%s, invalid=%s,\n"
- " trap_erange=%s, erange=%s,\n"
- " trap_divzero=%s, divzero=%s,\n"
- " trap_expbound=%s)"
- );
- #endif
- if (!format) {
- Py_DECREF(tuple);
- return NULL;
- }
- PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.mpfr_prec));
- #ifdef WITHMPC
- if (self->ctx.real_prec == GMPY_DEFAULT)
- PyTuple_SET_ITEM(tuple, i++, Py2or3String_FromString("Default"));
- else
- PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.real_prec));
- if (self->ctx.imag_prec == GMPY_DEFAULT)
- PyTuple_SET_ITEM(tuple, i++, Py2or3String_FromString("Default"));
- else
- PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.imag_prec));
- #endif
- PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.mpfr_round));
- #ifdef WITHMPC
- PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.real_round));
- PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.imag_round));
- #endif
- PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.emax));
- PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.emin));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.subnormalize));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_underflow));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.underflow));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_overflow));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.overflow));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_inexact));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.inexact));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_invalid));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.invalid));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_erange));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.erange));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_divzero));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.divzero));
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_expbound));
- #ifdef WITHMPC
- PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.allow_complex));
- #endif
- if (!PyErr_Occurred())
- result = Py2or3String_Format(format, tuple);
- else
- SYSTEM_ERROR("internal error in GMPyContext_repr");
- Py_DECREF(format);
- Py_DECREF(tuple);
- return result;
- };
- static PyObject *
- GMPyContextManager_repr(GMPyContextManagerObject *self)
- {
- return Py_BuildValue("s", "<gmpy2.ContextManagerObject>");
- }
- PyDoc_STRVAR(doc_get_context,
- "get_context() -> gmpy2 context\n\n"
- "Return a reference to the current context.");
- static PyObject *
- GMPyContext_get_context(PyObject *self, PyObject *args)
- {
- Py_INCREF((PyObject*)context);
- return (PyObject*)context;
- }
- PyDoc_STRVAR(doc_context_copy,
- "context.copy() -> gmpy2 context\n\n"
- "Return a copy of a context.");
- static PyObject *
- GMPyContext_context_copy(PyObject *self, PyObject *other)
- {
- GMPyContextObject *result;
- result = (GMPyContextObject*)GMPyContext_new();
- result->ctx = ((GMPyContextObject*)self)->ctx;
- return (PyObject*)result;
- }
- PyDoc_STRVAR(doc_local_context,
- "local_context([context[,keywords]]) -> context manager\n\n"
- "Create a context manager object that will restore the current context\n"
- "when the 'with ...' block terminates. The temporary context for the\n"
- "'with ...' block is based on the current context if no context is\n"
- "specified. Keyword arguments are supported and will modify the\n"
- "temporary new context.");
- static PyObject *
- GMPyContext_local_context(PyObject *self, PyObject *args, PyObject *kwargs)
- {
- GMPyContextManagerObject *result;
- PyObject *local_args = args;
- int arg_context = 0;
- #ifdef WITHMPC
- static char *kwlist[] = {
- "precision", "real_prec", "imag_prec", "round",
- "real_round", "imag_round", "emax", "emin", "subnormalize",
- "trap_underflow", "trap_overflow", "trap_inexact",
- "trap_invalid", "trap_erange", "trap_divzero",
- "trap_expbound", "allow_complex", NULL };
- #else
- static char *kwlist[] = {
- "precision", "round", "emax", "emin", "subnormalize",
- "trap_underflow", "trap_overflow", "trap_inexact",
- "trap_invalid", "trap_erange", "trap_divzero", "trap_expbound",
- NULL };
- #endif
- if (PyTuple_GET_SIZE(args) == 1 && GMPyContext_Check(PyTuple_GET_ITEM(args, 0))) {
- arg_context = 1;
- if (!(local_args = PyTuple_New(0)))
- return NULL;
- }
- else if (PyTuple_GET_SIZE(args)) {
- VALUE_ERROR("local_context() only supports [context[,keyword]] arguments");
- return NULL;
- }
- if (!(result = (GMPyContextManagerObject*)GMPyContextManager_new()))
- return NULL;
- if (arg_context) {
- result->new_ctx = ((GMPyContextObject*)PyTuple_GET_ITEM(args, 0))->ctx;
- }
- else {
- result->new_ctx = context->ctx;
- }
- result->old_ctx = context->ctx;
- #ifdef WITHMPC
- if (!(PyArg_ParseTupleAndKeywords(local_args, kwargs,
- "|llliiilliiiiiiiii", kwlist,
- &result->new_ctx.mpfr_prec,
- &result->new_ctx.real_prec,
- &result->new_ctx.imag_prec,
- &result->new_ctx.mpfr_round,
- &result->new_ctx.real_round,
- &result->new_ctx.imag_round,
- &result->new_ctx.emax,
- &result->new_ctx.emin,
- &result->new_ctx.subnormalize,
- &result->new_ctx.trap_underflow,
- &result->new_ctx.trap_overflow,
- &result->new_ctx.trap_inexact,
- &result->new_ctx.trap_invalid,
- &result->new_ctx.trap_erange,
- &result->new_ctx.trap_divzero,
- &result->new_ctx.trap_expbound,
- &result->new_ctx.allow_complex))) {
- #else
- if (!(PyArg_ParseTupleAndKeywords(local_args, kwargs,
- "|lilliiiiiiii", kwlist,
- &result->new_ctx.mpfr_prec,
- &result->new_ctx.mpfr_round,
- &result->new_ctx.emax,
- &result->new_ctx.emin,
- &result->new_ctx.subnormalize,
- &result->new_ctx.trap_underflow,
- &result->new_ctx.trap_overflow,
- &result->new_ctx.trap_inexact,
- &result->new_ctx.trap_invalid,
- &result->new_ctx.trap_erange,
- &result->new_ctx.trap_divzero,
- &result->new_ctx.trap_expbound))) {
- #endif
- VALUE_ERROR("invalid keyword arguments in local_context()");
- goto error;
- }
- /* Sanity check for values. */
- if (result->new_ctx.mpfr_prec < MPFR_PREC_MIN ||
- result->new_ctx.mpfr_prec > MPFR_PREC_MAX) {
- VALUE_ERROR("invalid value for precision");
- goto error;
- }
- #ifdef WITHMPC
- if (!(result->new_ctx.real_prec == GMPY_DEFAULT ||
- (result->new_ctx.real_prec >= MPFR_PREC_MIN &&
- result->new_ctx.real_prec <= MPFR_PREC_MAX))) {
- VALUE_ERROR("invalid value for real_prec");
- goto error;
- }
- if (!(result->new_ctx.imag_prec == GMPY_DEFAULT ||
- (result->new_ctx.imag_prec >= MPFR_PREC_MIN &&
- result->new_ctx.imag_prec <= MPFR_PREC_MAX))) {
- VALUE_ERROR("invalid value for imag_prec");
- goto error;
- }
- #endif
- if (!(result->new_ctx.mpfr_round == MPFR_RNDN ||
- result->new_ctx.mpfr_round == MPFR_RNDZ ||
- result->new_ctx.mpfr_round == MPFR_RNDU ||
- result->new_ctx.mpfr_round == MPFR_RNDD ||
- result->new_ctx.mpfr_round == MPFR_RNDA)) {
- VALUE_ERROR("invalid value for round");
- goto error;
- }
- #ifdef WITHMPC
- if (result->new_ctx.mpfr_round == MPFR_RNDA) {
- /* Since RNDA is not supported for MPC, set the MPC rounding modes
- * to MPFR_RNDN.
- */
- result->new_ctx.real_round = MPFR_RNDN;
- result->new_ctx.imag_round = MPFR_RNDN;
- }
- if (!(result->new_ctx.real_round == MPFR_RNDN ||
- result->new_ctx.real_round == MPFR_RNDZ ||
- result->new_ctx.real_round == MPFR_RNDU ||
- result->new_ctx.real_round == MPFR_RNDD ||
- result->new_ctx.real_round == GMPY_DEFAULT)) {
- VALUE_ERROR("invalid value for real_round");
- goto error;
- }
- if (!(result->new_ctx.imag_round == MPFR_RNDN ||
- result->new_ctx.imag_round == MPFR_RNDZ ||
- result->new_ctx.imag_round == MPFR_RNDU ||
- result->new_ctx.imag_round == MPFR_RNDD ||
- result->new_ctx.imag_round == GMPY_DEFAULT)) {
- VALUE_ERROR("invalid value for imag_round");
- goto error;
- }
- #endif
- if (!(result->new_ctx.emin < 0 && result->new_ctx.emax > 0)) {
- VALUE_ERROR("invalid values for emin and/or emax");
- goto error;
- }
- if (mpfr_set_emin(result->new_ctx.emin)) {
- VALUE_ERROR("invalid value for emin");
- goto error;
- }
- if (mpfr_set_emax(result->new_ctx.emax)) {
- VALUE_ERROR("invalid value for emax");
- goto error;
- }
- if (arg_context) {
- Py_DECREF(local_args);
- }
- return (PyObject*)result;
- error:
- if (arg_context) {
- Py_DECREF(local_args);
- }
- Py_DECREF((PyObject*)result);
- return NULL;
- }
- #ifdef WITHMPC
- PyDoc_STRVAR(doc_context,
- "context() -> context manager\n\n"
- "Return a new context for controlling MPFR and MPC arithmetic. To load\n"
- "the new context, use set_context(). Options can only be specified as\n"
- "keyword arguments. \n\n"
- " precision: precision, in bits, of an MPFR result\n"
- " real_prec: precision, in bits, of Re(MPC)\n"
- " -1 implies use mpfr_prec\n"
- " imag_prec: precision, in bits, of Im(MPC)\n"
- " -1 implies use real_prec\n"
- " round: rounding mode for MPFR\n"
- " real_round: rounding mode for Re(MPC)\n"
- " -1 implies use mpfr_round\n"
- " imag_round: rounding mode for Im(MPC)\n"
- " -1 implies use real_round\n"
- " e_max: maximum allowed exponent\n"
- " e_min: minimum allowed exponent\n"
- " subnormalize: if True, subnormalized results can be returned\n"
- " trap_underflow: if True, raise exception for underflow\n"
- " if False, set underflow flag\n"
- " trap_overflow: if True, raise exception for overflow\n"
- " if False, set overflow flag and return Inf or -Inf\n"
- " trap_inexact: if True, raise exception for inexact result\n"
- " if False, set inexact flag\n"
- " trap_invalid: if True, raise exception for invalid operation\n"
- " if False, set invalid flag and return NaN\n"
- " trap_erange: if True, raise exception for range error\n"
- " if False, set erange flag\n"
- " trap_divzero: if True, raise exception for division by zero\n"
- " if False, set divzero flag and return Inf or -Inf\n"
- " trap_expbound: if True, raise exception when mpfr/mpc exponent\n"
- " no longer valid in current context\n"
- " if False, mpfr/mpc with exponent out-of-bounds\n"
- " will be coerced to either 0 or Infinity\n"
- " allow_complex: if True, allow mpfr functions to return mpc\n"
- " if False, mpfr functions cannot return an mpc\n");
- #else
- PyDoc_STRVAR(doc_context,
- "context() -> context\n\n"
- "Return a new context for controlling MPFR arithmetic. To load the\n"
- "new context, use set_context(). Options can only be specified as\n"
- "keyword arguments. \n\n"
- " precision: precision, in bits, of an MPFR result\n"
- " round: rounding mode for MPFR\n"
- " e_max: maximum allowed exponent\n"
- " e_min: minimum allowed exponent\n"
- " subnormalize: if True, subnormalized results can be returned\n"
- " trap_underflow: if True, raise exception for underflow\n"
- " if False, set underflow flag\n"
- " trap_overflow: if True, raise exception for overflow\n"
- " if False, set overflow flag and return Inf or -Inf\n"
- " trap_inexact: if True, raise exception for inexact result\n"
- " if False, set inexact flag\n"
- " trap_invalid: if True, raise exception for invalid operation\n"
- " if False, set invalid flag and return NaN\n"
- " trap_erange: if True, raise exception for range error\n"
- " if False, set erange flag\n"
- " trap_divzero: if True, raise exception for division by zero\n"
- " if False, set divzero flag and return Inf or -Inf\n"
- " trap_expbound: if True, raise exception when mpfr/mpc exponent\n"
- " no longer valid in current context\n"
- " if False, mpfr/mpc with exponent out-of-bounds will\n"
- " coerced to either 0 or Infinity\n");
- #endif
- static PyObject *
- GMPyContext_context(PyObject *self, PyObject *args, PyObject *kwargs)
- {
- GMPyContextObject *result;
- #ifdef WITHMPC
- static char *kwlist[] = {
- "precision", "real_prec", "imag_prec", "round",
- "real_round", "imag_round", "emax", "emin", "subnormalize",
- "trap_underflow", "trap_overflow", "trap_inexact",
- "trap_invalid", "trap_erange", "trap_divzero", "trap_expbound",
- "allow_complex", NULL };
- #else
- static char *kwlist[] = {
- "precision", "round", "emax", "emin", "subnormalize",
- "trap_underflow", "trap_overflow", "trap_inexact",
- "trap_invalid", "trap_erange", "trap_divzero",
- "trap_expbound", NULL };
- #endif
- if (PyTuple_GET_SIZE(args)) {
- VALUE_ERROR("context() only supports keyword arguments");
- return NULL;
- }
- if (!(result = (GMPyContextObject*)GMPyContext_new()))
- return NULL;
- #ifdef WITHMPC
- if (!(PyArg_ParseTupleAndKeywords(args, kwargs,
- "|llliiilliiiiiiiii", kwlist,
- &result->ctx.mpfr_prec,
- &result->ctx.real_prec,
- &result->ctx.imag_prec,
- &result->ctx.mpfr_round,
- &result->ctx.real_round,
- &result->ctx.imag_round,
- &result->ctx.emax,
- &result->ctx.emin,
- &result->ctx.subnormalize,
- &result->ctx.trap_underflow,
- &result->ctx.trap_overflow,
- &result->ctx.trap_inexact,
- &result->ctx.trap_invalid,
- &result->ctx.trap_erange,
- &result->ctx.trap_divzero,
- &result->ctx.trap_expbound,
- &result->ctx.allow_complex))) {
- #else
- if (!(PyArg_ParseTupleAndKeywords(args, kwargs,
- "|lilliiiiiiii", kwlist,
- &result->ctx.mpfr_prec,
- &result->ctx.mpfr_round,
- &result->ctx.emax,
- &result->ctx.emin,
- &result->ctx.subnormalize,
- &result->ctx.trap_underflow,
- &result->ctx.trap_overflow,
- &result->ctx.trap_inexact,
- &result->ctx.trap_invalid,
- &result->ctx.trap_erange,
- &result->ctx.trap_divzero,
- &result->ctx.trap_expbound))) {
- #endif
- VALUE_ERROR("invalid keyword arguments in context()");
- return NULL;
- }
- /* Sanity check for values. */
- if (result->ctx.mpfr_prec < MPFR_PREC_MIN ||
- result->ctx.mpfr_prec > MPFR_PREC_MAX) {
- Py_DECREF((PyObject*)result);
- VALUE_ERROR("invalid value for precision");
- return NULL;
- }
- #ifdef WITHMPC
- if (!(result->ctx.real_prec == GMPY_DEFAULT ||
- (result->ctx.real_prec >= MPFR_PREC_MIN &&
- result->ctx.real_prec <= MPFR_PREC_MAX))) {
- Py_DECREF((PyObject*)result);
- VALUE_ERROR("invalid value for real_prec");
- return NULL;
- }
- if (!(result->ctx.imag_prec == GMPY_DEFAULT ||
- (result->ctx.imag_prec >= MPFR_PREC_MIN &&
- result->ctx.imag_prec <= MPFR_PREC_MAX))) {
- Py_DECREF((PyObject*)result);
- VALUE_ERROR("invalid value for imag_prec");
- return NULL;
- }
- #endif
- if (!(result->ctx.mpfr_round == MPFR_RNDN ||
- result->ctx.mpfr_round == MPFR_RNDZ ||
- result->ctx.mpfr_round == MPFR_RNDU ||
- result->ctx.mpfr_round == MPFR_RNDD ||
- result->ctx.mpfr_round == MPFR_RNDA)) {
- Py_DECREF((PyObject*)result);
- VALUE_ERROR("invalid value for round");
- return NULL;
- }
- #ifdef WITHMPC
- if (result->ctx.mpfr_round == MPFR_RNDA) {
- /* Since RNDA is not supported for MPC, set the MPC rounding modes
- to MPFR_RNDN. */
- result->ctx.real_round = MPFR_RNDN;
- result->ctx.imag_round = MPFR_RNDN;
- }
- if (!(result->ctx.real_round == MPFR_RNDN ||
- result->ctx.real_round == MPFR_RNDZ ||
- result->ctx.real_round == MPFR_RNDU ||
- result->ctx.real_round == MPFR_RNDD ||
- result->ctx.real_round == GMPY_DEFAULT)) {
- Py_DECREF((PyObject*)result);
- VALUE_ERROR("invalid value for real_round");
- return NULL;
- }
- if (!(result->ctx.imag_round == MPFR_RNDN ||
- result->ctx.imag_round == MPFR_RNDZ ||
- result->ctx.imag_round == MPFR_RNDU ||
- result->ctx.imag_round == MPFR_RNDD ||
- result->ctx.imag_round == GMPY_DEFAULT)) {
- Py_DECREF((PyObject*)result);
- VALUE_ERROR("invalid value for imag_round");
- return NULL;
- }
- #endif
- if (!(result->ctx.emin < 0 && result->ctx.emax > 0)) {
- VALUE_ERROR("invalid values for emin and/or emax");
- Py_DECREF((PyObject*)result);
- return NULL;
- }
- if (mpfr_set_emin(result->ctx.emin)) {
- VALUE_ERROR("invalid value for emin");
- Py_DECREF((PyObject*)result);
- return NULL;
- }
- if (mpfr_set_emax(result->ctx.emax)) {
- VALUE_ERROR("invalid value for emax");
- Py_DECREF((PyObject*)result);
- return NULL;
- }
- result->ctx.underflow = 0;
- result->ctx.overflow = 0;
- result->ctx.inexact = 0;
- result->ctx.invalid = 0;
- result->ctx.erange = 0;
- result->ctx.divzero = 0;
- return (PyObject*)result;
- }
- PyDoc_STRVAR(doc_set_context,
- "set_context(context)\n\n"
- "Activate a context object controlling MPFR and MPC arithmetic.\n");
- static PyObject *
- GMPyContext_set_context(PyObject *self, PyObject *other)
- {
- if (GMPyContext_Check(other)) {
- Py_INCREF((PyObject*)other);
- Py_DECREF((PyObject*)context);
- context = (GMPyContextObject*)other;
- mpfr_set_emin(context->ctx.emin);
- mpfr_set_emax(context->ctx.emax);
- Py_RETURN_NONE;
- }
- else {
- VALUE_ERROR("set_context() requires a context argument");
- return NULL;
- }
- }
- static PyObject *
- GMPyContextManager_enter(PyObject *self, PyObject *args)
- {
- GMPyContextObject *result;
- if (!(result = (GMPyContextObject*)GMPyContext_new()))
- return NULL;
- result->ctx = ((GMPyContextManagerObject*)self)->new_ctx;
- Py_DECREF((PyObject*)context);
- context = (GMPyContextObject*)result;
- Py_INCREF((PyObject*)context);
- mpfr_set_emin(context->ctx.emin);
- mpfr_set_emax(context->ctx.emax);
- return (PyObject*)result;
- }
- static PyObject *
- GMPyContextManager_exit(PyObject *self, PyObject *args)
- {
- GMPyContextObject *result;
- if (!(result = (GMPyContextObject*)GMPyContext_new()))
- return NULL;
- result->ctx = ((GMPyContextManagerObject*)self)->old_ctx;
- Py_DECREF((PyObject*)context);
- context = (GMPyContextObject*)result;
- mpfr_set_emin(context->ctx.emin);
- mpfr_set_emax(context->ctx.emax);
- Py_RETURN_NONE;
- }
- static PyObject *
- GMPyContext_enter(PyObject *self, PyObject *args)
- {
- GMPyContextObject *result;
- if (!(result = (GMPyContextObject*)GMPyContext_new()))
- return NULL;
- result->ctx = ((GMPyContextObject*)self)->ctx;
- Py_DECREF((PyObject*)context);
- context = (GMPyContextObject*)result;
- Py_INCREF((PyObject*)context);
- mpfr_set_emin(context->ctx.emin);
- mpfr_set_emax(context->ctx.emax);
- return (PyObject*)result;
- }
- static PyObject *
- GMPyContext_exit(PyObject *self, PyObject *args)
- {
- Py_DECREF((PyObject*)context);
- context = (GMPyContextObject*)self;
- Py_INCREF((PyObject*)context);
- mpfr_set_emin(context->ctx.emin);
- mpfr_set_emax(context->ctx.emax);
- Py_RETURN_NONE;
- }
- PyDoc_STRVAR(doc_context_clear_flags,
- "clear_flags()\n\n"
- "Clear all MPFR exception flags.");
- static PyObject *
- GMPyContext_clear_flags(PyObject *self, PyObject *args)
- {
- ((GMPyContextObject*)self)->ctx.underflow = 0;
- ((GMPyContextObject*)self)->ctx.overflow = 0;
- ((GMPyContextObject*)self)->ctx.inexact = 0;
- ((GMPyContextObject*)self)->ctx.invalid = 0;
- ((GMPyContextObject*)self)->ctx.erange = 0;
- ((GMPyContextObject*)self)->ctx.divzero = 0;
- Py_RETURN_NONE;
- }
- /* Define the get/set functions. */
- #define GETSET_BOOLEAN(NAME) \
- static PyObject * \
- GMPyContext_get_##NAME(GMPyContextObject *self, void *closure) \
- { \
- return PyBool_FromLong(self->ctx.NAME); \
- }; \
- static int \
- GMPyContext_set_##NAME(GMPyContextObject *self, PyObject *value, void *closure) \
- { \
- if (!(PyBool_Check(value))) { \
- TYPE_ERROR(#NAME " must be True or False"); \
- return -1; \
- } \
- self->ctx.NAME = (value == Py_True) ? 1 : 0; \
- return 0; \
- }
- GETSET_BOOLEAN(subnormalize);
- GETSET_BOOLEAN(underflow);
- GETSET_BOOLEAN(overflow);
- GETSET_BOOLEAN(inexact);
- GETSET_BOOLEAN(invalid);
- GETSET_BOOLEAN(erange);
- GETSET_BOOLEAN(divzero);
- GETSET_BOOLEAN(trap_underflow);
- GETSET_BOOLEAN(trap_overflow);
- GETSET_BOOLEAN(trap_inexact);
- GETSET_BOOLEAN(trap_invalid);
- GETSET_BOOLEAN(trap_erange);
- GETSET_BOOLEAN(trap_divzero);
- GETSET_BOOLEAN(trap_expbound);
- #ifdef WITHMPC
- GETSET_BOOLEAN(allow_complex)
- #endif
- static PyObject *
- GMPyContext_get_precision(GMPyContextObject *self, void *closure)
- {
- return PyIntOrLong_FromSsize_t((Py_ssize_t)(self->ctx.mpfr_prec));
- }
- static int
- GMPyContext_set_precision(GMPyContextObject *self, PyObject *value, void *closure)
- {
- Py_ssize_t temp;
- if (!(PyIntOrLong_Check(value))) {
- TYPE_ERROR("precision must be Python integer");
- return -1;
- }
- temp = PyIntOrLong_AsSsize_t(value);
- if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX || PyErr_Occurred()) {
- VALUE_ERROR("invalid value for precision");
- return -1;
- }
- self->ctx.mpfr_prec = (mpfr_prec_t)temp;
- return 0;
- }
- #ifdef WITHMPC
- static PyObject *
- GMPyContext_get_real_prec(GMPyContextObject *self, void *closure)
- {
- return PyIntOrLong_FromSsize_t((Py_ssize_t)(GET_REAL_PREC(self)));
- }
- static int
- GMPyContext_set_real_prec(GMPyContextObject *self, PyObject *value, void *closure)
- {
- Py_ssize_t temp;
- if (!(PyIntOrLong_Check(value))) {
- TYPE_ERROR("real_prec must be Python integer");
- return -1;
- }
- temp = PyIntOrLong_AsSsize_t(value);
- if (temp == -1) {
- if (PyErr_Occurred()) {
- VALUE_ERROR("invalid value for real_prec");
- return -1;
- }
- }
- else if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX) {
- VALUE_ERROR("invalid value for real_prec");
- return -1;
- }
- self->ctx.real_prec = (mpfr_prec_t)temp;
- return 0;
- }
- static PyObject *
- GMPyContext_get_imag_prec(GMPyContextObject *self, void *closure)
- {
- return PyIntOrLong_FromSsize_t((Py_ssize_t)(GET_IMAG_PREC(self)));
- }
- static int
- GMPyContext_set_imag_prec(GMPyContextObject *self, PyObject *value, void *closure)
- {
- Py_ssize_t temp;
- if (!(PyIntOrLong_Check(value))) {
- TYPE_ERROR("imag_prec must be Python integer");
- return -1;
- }
- temp = PyIntOrLong_AsSsize_t(value);
- if (temp == -1) {
- if (PyErr_Occurred()) {
- VALUE_ERROR("invalid value for imag_prec");
- return -1;
- }
- }
- else if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX) {
- VALUE_ERROR("invalid value for imag_prec");
- return -1;
- }
- self->ctx.imag_prec = (mpfr_prec_t)temp;
- return 0;
- }
- #endif
- static PyObject *
- GMPyContext_get_round(GMPyContextObject *self, void *closure)
- {
- return PyIntOrLong_FromLong((long)(self->ctx.mpfr_round));
- }
- static int
- GMPyContext_set_round(GMPyContextObject *self, PyObject *value, void *closure)
- {
- long temp;
- if (!(PyIntOrLong_Check(value))) {
- TYPE_ERROR("round mode must be Python integer");
- return -1;
- }
- temp = PyIntOrLong_AsLong(value);
- if (temp == -1 && PyErr_Occurred()) {
- VALUE_ERROR("invalid value for round mode");
- return -1;
- }
- if (temp == MPFR_RNDN)
- self->ctx.mpfr_round = MPFR_RNDN;
- else if (temp == MPFR_RNDZ)
- self->ctx.mpfr_round = MPFR_RNDZ;
- else if (temp == MPFR_RNDU)
- self->ctx.mpfr_round = MPFR_RNDU;
- else if (temp == MPFR_RNDD)
- self->ctx.mpfr_round = MPFR_RNDD;
- else if (temp == MPFR_RNDA) {
- self->ctx.mpfr_round = MPFR_RNDA;
- #ifdef WITHMPC
- /* Since RNDA is not supported for MPC, set the MPC rounding modes
- to MPFR_RNDN. */
- self->ctx.real_round = MPFR_RNDN;
- self->ctx.imag_round = MPFR_RNDN;
- #endif
- }
- else {
- VALUE_ERROR("invalid value for round mode");
- return -1;
- }
- return 0;
- }
- #ifdef WITHMPC
- static PyObject *
- GMPyContext_get_real_round(GMPyContextObject *self, void *closure)
- {
- return PyIntOrLong_FromLong((long)GET_REAL_ROUND(self));
- }
- static int
- GMPyContext_set_real_round(GMPyContextObject *self, PyObject *value, void *closure)
- {
- long temp;
- if (!(PyIntOrLong_Check(value))) {
- TYPE_ERROR("round mode must be Python integer");
- return -1;
- }
- temp = PyIntOrLong_AsLong(value);
- if (temp == -1 && PyErr_Occurred()) {
- VALUE_ERROR("invalid value for round mode");
- return -1;
- }
- if (temp == GMPY_DEFAULT || temp == MPFR_RNDN || temp == MPFR_RNDZ ||
- temp == MPFR_RNDU || temp == MPFR_RNDD) {
- self->ctx.real_round = (int)temp;
- }
- else {
- VALUE_ERROR("invalid value for round mode");
- return -1;
- }
- return 0;
- }
- static PyObject *
- GMPyContext_get_imag_round(GMPyContextObject *self, void *closure)
- {
- return PyIntOrLong_FromLong((long)GET_IMAG_ROUND(self));
- }
- static int
- GMPyContext_set_imag_round(GMPyContextObject *self, PyObject *value, void *closure)
- {
- long temp;
- if (!(PyIntOrLong_Check(value))) {
- TYPE_ERROR("round mode must be Python integer");
- return -1;
- }
- temp = PyIntOrLong_AsLong(value);
- if (temp == -1 && PyErr_Occurred()) {
- VALUE_ERROR("invalid value for round mode");
- return -1;
- }
- if (temp == GMPY_DEFAULT || temp == MPFR_RNDN || temp == MPFR_RNDZ ||
- temp == MPFR_RNDU || temp == MPFR_RNDD) {
- self->ctx.imag_round = (int)temp;
- }
- else {
- VALUE_ERROR("invalid value for round mode");
- return -1;
- }
- return 0;
- }
- #endif
- static PyObject *
- GMPyContext_get_emin(GMPyContextObject *self, void *closure)
- {
- return PyIntOrLong_FromLong(self->ctx.emin);
- }
- static int
- GMPyContext_set_emin(GMPyContextObject *self, PyObject *value, void *closure)
- {
- long exp;
- if (!(PyIntOrLong_Check(value))) {
- TYPE_ERROR("emin must be Python integer");
- return -1;
- }
- exp = PyIntOrLong_AsLong(value);
- if (exp == -1 && PyErr_Occurred()) {
- VALUE_ERROR("requested minimum exponent is invalid");
- return -1;
- }
- if (mpfr_set_emin((mpfr_prec_t)exp)) {
- VALUE_ERROR("requested minimum exponent is invalid");
- return -1;
- }
- self->ctx.emin = exp;
- mpfr_set_emin(exp);
- return 0;
- }
- static PyObject *
- GMPyContext_get_emax(GMPyContextObject *self, void *closure)
- {
- return PyIntOrLong_FromLong(self->ctx.emax);
- }
- static int
- GMPyContext_set_emax(GMPyContextObject *self, PyObject *value, void *closure)
- {
- long exp;
- if (!(PyIntOrLong_Check(value))) {
- TYPE_ERROR("emax must be Python integer");
- return -1;
- }
- exp = PyIntOrLong_AsLong(value);
- if (exp == -1 && PyErr_Occurred()) {
- VALUE_ERROR("requested maximum exponent is invalid");
- return -1;
- }
- if (mpfr_set_emax((mpfr_prec_t)exp)) {
- VALUE_ERROR("requested maximum exponent is invalid");
- return -1;
- }
- self->ctx.emax = exp;
- mpfr_set_emax(exp);
- return 0;
- }
- #define ADD_GETSET(NAME) \
- {#NAME, \
- (getter)GMPyContext_get_##NAME, \
- (setter)GMPyContext_set_##NAME, NULL, NULL}
- static PyGetSetDef GMPyContext_getseters[] = {
- ADD_GETSET(precision),
- #ifdef WITHMPC
- ADD_GETSET(real_prec),
- ADD_GETSET(imag_prec),
- #endif
- ADD_GETSET(round),
- #ifdef WITHMPC
- ADD_GETSET(real_round),
- ADD_GETSET(imag_round),
- #endif
- ADD_GETSET(emax),
- ADD_GETSET(emin),
- ADD_GETSET(subnormalize),
- ADD_GETSET(underflow),
- ADD_GETSET(overflow),
- ADD_GETSET(inexact),
- ADD_GETSET(invalid),
- ADD_GETSET(erange),
- ADD_GETSET(divzero),
- ADD_GETSET(trap_underflow),
- ADD_GETSET(trap_overflow),
- ADD_GETSET(trap_inexact),
- ADD_GETSET(trap_invalid),
- ADD_GETSET(trap_erange),
- ADD_GETSET(trap_divzero),
- ADD_GETSET(trap_expbound),
- #ifdef WITHMPC
- ADD_GETSET(allow_complex),
- #endif
- {NULL}
- };
- static PyMethodDef GMPyContext_methods[] =
- {
- { "clear_flags", GMPyContext_clear_flags, METH_NOARGS,
- doc_context_clear_flags },
- { "copy", GMPyContext_context_copy, METH_NOARGS, doc_context_copy },
- { "__enter__", GMPyContext_enter, METH_NOARGS, NULL },
- { "__exit__", GMPyContext_exit, METH_VARARGS, NULL },
- { NULL, NULL, 1 }
- };
- static PyTypeObject GMPyContext_Type =
- {
- #ifdef PY3
- PyVarObject_HEAD_INIT(0, 0)
- #else
- PyObject_HEAD_INIT(0)
- 0, /* ob_size */
- #endif
- "gmpy2 context", /* tp_name */
- sizeof(GMPyContextObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor) GMPyContext_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- (reprfunc) GMPyContext_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- "GMPY2 Context Object", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset*/
- 0, /* tp_iter */
- 0, /* tp_iternext */
- GMPyContext_methods, /* tp_methods */
- 0, /* tp_members */
- GMPyContext_getseters, /* tp_getset */
- };
- static PyMethodDef GMPyContextManager_methods[] =
- {
- { "__enter__", GMPyContextManager_enter, METH_NOARGS, NULL },
- { "__exit__", GMPyContextManager_exit, METH_VARARGS, NULL },
- { NULL, NULL, 1 }
- };
- static PyTypeObject GMPyContextManager_Type =
- {
- #ifdef PY3
- PyVarObject_HEAD_INIT(0, 0)
- #else
- PyObject_HEAD_INIT(0)
- 0, /* ob_size */
- #endif
- "gmpy2 context", /* tp_name */
- sizeof(GMPyContextManagerObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor) GMPyContextManager_dealloc, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- (reprfunc) GMPyContextManager_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- "GMPY2 Context manager", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset*/
- 0, /* tp_iter */
- 0, /* tp_iternext */
- GMPyContextManager_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- };